package com.linkgie.galaxyframework.crypto;

/**
 * 编解码器；
 * <p>
 * 
 * 通过 {@link CryptoCodec} 可以实现把密码对象编码输出为二进制字节数据，或者解析二进制字节数组生成密码对象；
 * 
 * @author liso
 *
 */
public interface CryptoCodec {

	/**
	 * 把哈希摘要编码输出为字节数组；
	 * 
	 * @param hashCode
	 * @return
	 */
	byte[] encode(HashCode hashCode);

	/**
	 * 把签名输出为字节数组；
	 * 
	 * @param signature
	 * @return
	 */
	byte[] encode(Signature signature);

	/**
	 * 把私钥输出为字节数组；
	 * 
	 * @param privateKey
	 * @return
	 */
	byte[] encode(PrivateKey privateKey);

	/**
	 * 把公钥输出为字节数组；
	 * 
	 * @param publicKey
	 * @return
	 */
	byte[] encode(PublicKey publicKey);

	/**
	 * 把密钥输出为字节数组；
	 * 
	 * @param secretKey
	 * @return
	 */
	byte[] encode(SymmetricKey secretKey);

	/**
	 * 解码指定的密码字节采用的密码算法；
	 * <p>
	 * 如果无法识别格式，或算法不支持，则返回 null；
	 * 
	 * @param cryptoBytes
	 * @return
	 */
	Algorithm decodeAlgorithm(byte[] cryptoBytes);

	/**
	 * 解码指定的密码字节的类型；
	 * <p>
	 * 
	 * 如果无法识别算法类型，或者无法识别密码数据类型，则返回 null；
	 * 
	 * @param cryptoBytes 密码数据
	 * @return 密码数据类型；
	 */
	CryptogramType decodeType(byte[] cryptoBytes);

	/**
	 * 验证指定的密码字节的算法和类型；
	 * <p>
	 * 
	 * 如果是指定的算法以及类型，则返回 true； 否则返回 false；
	 * 
	 * @param cryptoBytes 密码数据；
	 * @param algorithm   算法；
	 * @param type        密码数据类型；
	 * @return
	 */
	boolean check(byte[] cryptoBytes, String algorithm, CryptogramType type);

	/**
	 * 解码指定的密码字节为指定的密码对象；
	 * <p>
	 * 
	 * 如果无法识别算法类型，或者无法识别密码数据类型，则返回 null；
	 * 
	 * @param cryptoBytes 密码数据
	 * @param type        密码数据类型；
	 * @return 密码数据对象
	 */
	Cryptogram decode(byte[] cryptoBytes);

	/**
	 * 解码指定的密码字符为指定的密码对象；
	 * <p>
	 * 
	 * 如果无法识别算法类型，或者无法识别密码数据类型，则返回 null；
	 * 
	 * @param cryptoText 密码数据
	 * @param type       密码数据类型；
	 * @return 密码数据对象
	 */
	default Cryptogram decode(String cryptoText) {
		return decode(decodeToBytes(cryptoText));
	}

	/**
	 * 解码指定的密码字节为指定的密码对象；
	 * <p>
	 * 
	 * 如果无法识别算法类型，或者无法识别密码数据类型，则返回 null；
	 * 
	 * @param <T>         密码对象类型；必须是 {@link Cryptogram} 的子类型
	 *                    {@link HashCode}、{@link PublicKey}、{@link PrivateKey}、{@link Signature}、{@link SymmetricKey}
	 *                    之一；
	 * @param cryptoBytes 密码数据
	 * @param type        密码数据类型；
	 * @return 密码数据对象
	 */
	<T extends Cryptogram> T decode(byte[] cryptoBytes, Class<T> type);

	/**
	 * 解码指定的密码字符为指定的密码对象；
	 * <p>
	 * 
	 * 如果无法识别算法类型，或者无法识别密码数据类型，则返回 null；
	 * 
	 * @param <T>        密码对象类型；必须是 {@link Cryptogram} 的子类型
	 *                   {@link HashCode}、{@link PublicKey}、{@link PrivateKey}、{@link Signature}、{@link SymmetricKey}
	 *                   之一；
	 * @param cryptoText 密码数据
	 * @param type       密码数据类型；
	 * @return 密码数据对象
	 */
	default <T extends Cryptogram> T decode(String cryptoText, Class<T> type) {
		return decode(decodeToBytes(cryptoText), type);
	}

	/**
	 * 解码指定的密码字符为字节数组形式；
	 * 
	 * @param cryptoText
	 * @return
	 */
	byte[] decodeToBytes(String cryptoText);

	/**
	 * 解码指定的密码字节为指定的密码对象；
	 * <p>
	 * 如果算法类型和密码对象类型不匹配，则会引发异常，例如，algorithm 为 SM3， 密码对象类型为 {@link PublicKey} ；
	 * <p>
	 * 如果无法识别算法类型，或者无法识别密码数据类型，则返回 null；
	 * 
	 * @param <T>            密码对象类型；必须是 {@link Cryptogram} 的子类型
	 *                       {@link HashCode}、{@link PublicKey}、{@link PrivateKey}、{@link Signature}、{@link SymmetricKey}
	 *                       之一；
	 * @param algorithm      算法名称
	 * @param rawCryptoBytes 原始的密码数据
	 * @param type           密码数据类型；
	 * @return 密码数据对象
	 */
	<T extends Cryptogram> T decode(String algorithm, byte[] rawCryptoBytes, Class<T> type);
}
